<?php
/**
 * 工厂模式和简单工厂
 * 创建型设计模式
 */
spl_autoload_register('autoload');

function autoload($class) 
{
    require dirname($_SERVER['SCRIPT_FILENAME']) . '//..//' . str_replace('\\', '/', $class) . '.php';
}

/*============================= 测试 =============================*/

//简单工厂模式
use factory\SampleFactory;

$result = SampleFactory::create('+')->getResult(10, 20); //getResult可以不关注，只关注create操作
echo "$result\n";
$result = SampleFactory::create('-')->getResult(20, 10);
echo "$result\n";
$result = SampleFactory::create('*')->getResult(10, 20);
echo "$result\n";
$result = SampleFactory::create('/')->getResult(100, 20);
echo "$result\n";

//工厂方法模式
use factory\AddFactory;
$operFactory = AddFactory::getInstance(); //如果Add类名发生变化，而AddFactory类名是固定不变的，不影响客户端的使用，Add类却可任意修改，实现了客户端与底层类的解耦
//也就是说相当于在Add类外面再包一层AddFactory，以后都固定不变，至于Add类名和代码都可以任意修改
$result = $operFactory->getResult(10, 20);
echo "$result\n";


/*
小结：
    应用场景
    主要用在有创建大量对象的场景，此时需要将对象的创建和使用进行解耦
    避免需要生产的类名一修改，所有文件中的此类名都要修改，而在工厂模式中工厂类名可以保持固定不变

    简单工厂模式
    适合在一开始就很明确的固定的几个类需要实例化的场景
    优点：将对象的创建和使用进行了解耦，客户端不用关心使用了哪个类，只需要传递一个参数来决定实例化哪个类，一旦底层类名发生变化，参数保持不变，只需要修改new一处即可。
    缺点：违背了开闭原则，因为每加一个新的类，就得在创建方法（生产方法）中增加一个判断分支。
         为了解决这个问题，因此就有了工厂方法模式。

    工厂方法模式
    为了解决简单工厂中多分支判断的问题，把每个需要实例化的类再包一层，定义一个用于创建对象的接口，让子类决定实例化哪一个类。
    工厂方法使一个类的实例化延迟到其子类。
    工厂方法模式就会把简单工厂模式里的内部多分支判断，移到客户端代码中来做。
*/




